package com.lb.api;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.lb.api.ApiResultCodeEnum.*;


/**
 * 统一异常处理（增强）
 *
 * @author mingzhi.xie
 * @since 1.0
 */
@Slf4j
@RestControllerAdvice
public class ApiExceptionHandlerAdvice {

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ApiResult<?> exceptionHandler(MissingServletRequestParameterException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.build(REQUEST_PARAMETER_ERROR);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult<?> exceptionHandler(MethodArgumentNotValidException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.build(REQUEST_PARAMETER_ERROR, ex.getMessage(), null);
    }
    
    @ExceptionHandler(BindException.class)
    public ApiResult<?> exceptionHandler(BindException ex) {
        log.error(ex.getMessage(), ex);
        String message = Optional.ofNullable(ex.getBindingResult().getFieldError())
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .orElse(REQUEST_PARAMETER_ERROR.getReason());
        return ApiResult.build(REQUEST_PARAMETER_ERROR, message, null);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ApiResult<?> exceptionHandler(ConstraintViolationException ex) {
        log.error(ex.getMessage(), ex);
        String errMessage = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(";"));
        return ApiResult.build(REQUEST_PARAMETER_ERROR, errMessage, null);
    }

    @ExceptionHandler(ApiException.class)
    public ApiResult<?> exceptionHandler(ApiException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.build(ex.getCode());
    }

    @ExceptionHandler(Exception.class)
    public ApiResult<?> exceptionHandler(Exception ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.build(ERROR);
    }
}
